package cn.wizzer.app.user.modules.service.impl;

import cn.wizzer.app.crown.modules.models.CrownOrder;
import cn.wizzer.app.sys.modules.models.SysParam;
import cn.wizzer.app.sys.modules.services.SysParamService;
import cn.wizzer.app.user.modules.models.User;
import cn.wizzer.app.user.modules.models.UserRebate;
import cn.wizzer.app.user.modules.models.enums.BizTypeEnum;
import cn.wizzer.app.user.modules.models.enums.UserColEnum;
import cn.wizzer.app.user.modules.models.vo.UserRebateVO;
import cn.wizzer.app.user.modules.services.UserService;
import cn.wizzer.app.user.modules.services.account.UserAccountRecordService;
import cn.wizzer.app.user.modules.services.account.UserAccountService;
import cn.wizzer.app.user.modules.services.account.UserRebateService;
import cn.wizzer.framework.base.model.enums.BizExceptionEnum;
import cn.wizzer.framework.base.service.BaseServiceImpl;
import cn.wizzer.framework.base.service.CommonDBService;
import cn.wizzer.framework.page.Pagination;
import cn.wizzer.framework.util.Id;
import cn.wizzer.framework.util.Result;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import jnr.ffi.Struct;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.Times;
import org.nutz.log.Log;
import org.nutz.log.Logs;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * @author zl
 * @date 2020/8/7 15:45
 */
@IocBean(args = {"refer:dao"})
@Service(interfaceClass = UserRebateService.class)
public class UserRebateServiceImpl extends BaseServiceImpl<UserRebate> implements UserRebateService {
    public UserRebateServiceImpl(Dao dao) {
        super(dao);
    }

    private static final Log log = Logs.get();

    @Inject
    @Reference
    private SysParamService sysParamService;
    @Inject
    private UserService userService;
    @Inject
    private UserAccountRecordService userAccountRecordService;
    @Inject
    private CommonDBService dbService;
    @Inject
    private UserAccountService userAccountService;

    @Aop(TransAop.REPEATABLE_READ)
    @Override
    public void settleRebate(CrownOrder order) {
        log.info("计算返佣 order" + order);
        // 如果是体验金投注，则直接返回
        if (order.getExpInvest()) {
            return;
        }
        SysParam sysParam = sysParamService.fetch();
        String userId = order.getUserId();
        //返佣来源用户
        User fromUser = userService.fetch(userId);
        String[] toUserArr = fromUser.getPath().split("/");
        //上级人数
        int superiorNum = toUserArr.length - 1;
        //有效返佣层级
        Integer layer = sysParam.getRebateValidLayer();
        //有效返佣层级大于0且用户存在上级时
        if (layer > 0 && superiorNum > 0) {
            if (layer > superiorNum) {
                layer = superiorNum;
            }
            //订单金额(操作金额)
            BigDecimal oprMoney = order.getAmount();
            //返佣比例
            BigDecimal superRate = BigDecimal.valueOf(sysParam.getSuperRate()).divide(BigDecimal.valueOf(10000), 6, RoundingMode.DOWN);
            //返佣金额 = 订单金额 * 返佣比例 10000 *0.005 = 50
            BigDecimal rebateAmountBase = oprMoney.multiply(superRate).setScale(2, RoundingMode.DOWN);
            log.info("返水金额基数 rebateAmountBase:" + rebateAmountBase);
            if (rebateAmountBase.compareTo(BigDecimal.ZERO) > 0) {
                //层级比例
                BigDecimal levelRate = BigDecimal.valueOf(sysParam.getLevelRate()).divide(BigDecimal.valueOf(100), 2, RoundingMode.DOWN);
                //创建用户返佣对象
                UserRebate userRebate = new UserRebate();
                userRebate.setFromUser(fromUser.getId());
                userRebate.setOprMoney(oprMoney);
                userRebate.setOrderId(order.getId());
                for (int i = 1; i <= layer; i++) {
                    userRebate.setNo(Id.createOrderNo());
                    // 这边开始改
                    User toUser = userService.fetch(toUserArr[toUserArr.length - i - 1]);
                    // 上级账户金额大于100$才发放返佣
                    BigDecimal totalBalance = userAccountService.calTotalBalance(toUser.getId());
                    log.info("层级 layer" + i + ",账户余额" + totalBalance);
                    if (totalBalance.compareTo(BigDecimal.valueOf(100)) < 0) {
                        continue;
                    }
                    //
                    //个人返佣 = 返佣金额 * 层级比例

                    // 计算出百分比的几次方 占比多少
                    Double percent = Math.pow(Double.valueOf(levelRate.toString()), i);
                    BigDecimal rebateMoney = rebateAmountBase.multiply(new BigDecimal(percent.toString())).setScale(2, RoundingMode.DOWN);
                    //返佣保留小数点后两位后为0则跳出循环，不添加之后的返佣、流水记录
                    if (rebateMoney.compareTo(BigDecimal.ZERO) == 0) {
                        break;
                    }
                    userRebate.setId(null);
                    userRebate.setCtAt(System.currentTimeMillis());
                    userRebate.setRelationLevel(i);
                    userRebate.setToUser(toUser.getId());
                    userRebate.setRebateMoney(rebateMoney);
                    //添加返佣记录
                    this.insert(userRebate);
                    if (Strings.isBlank(userRebate.getId())) {
                        Result.breakWith(BizExceptionEnum.ADD_FAIL);
                    }
                    //添加流水
                    userAccountRecordService.add("default", toUser.getId(), rebateMoney, BizTypeEnum.SUB_REBATE, userRebate.getId(), userRebate.getNo());
                }
            }
        }
    }

    @Override
    public Pagination listPage(String conditionData, String orderNo, String fromUserSearch, String toUserSearch, String[] searchDate, int pageNumber, int pageSize) {

        StringBuffer sb = new StringBuffer();
        sb.append(" SELECT ur.*, o.no orderNo,");
        sb.append(" u1.email fromEmail, u1.nickName fromNickName, u1.userName fromUserName,");
        sb.append(" u2.email toEmail, u2.nickName toNickName, u2.userName toUserName");
        sb.append(" FROM user_rebate ur");
        sb.append(" LEFT JOIN crown_order o ON ur.orderId = o.id");
        sb.append(" LEFT JOIN user u1 ON ur.fromUser = u1.id");
        sb.append(" LEFT JOIN user u2 ON ur.toUser = u2.id");
        sb.append(" WHERE 1=1");
        if (Strings.isNotBlank(conditionData)) {
            String[] split = conditionData.split(",");
            for (String col : split) {
                String colName = UserColEnum.getValByName(col);
                if (Strings.isNotBlank(colName)) {
                    // 默认不显示游客、内部账号
                    sb.append(" AND u2.").append(colName).append(" = 0");
                }
            }
        }
        if (Strings.isNotBlank(orderNo)) {
            sb.append(" AND o.no = '").append(orderNo).append("'");
        }

        // 按昵称/邮箱/订单号搜索
        if (Strings.isNotBlank(fromUserSearch)) {
            sb.append(" AND u1.userName = '").append(fromUserSearch).append("'");
        }
        if (Strings.isNotBlank(toUserSearch)) {
            sb.append(" AND u2.userName = '").append(toUserSearch).append("'");
        }
        // 按时间搜索
        if (null != searchDate && searchDate.length != 0) {
            sb.append(" and ur.ctAt >=").append(Times.d2TS(Times.D(searchDate[0])) * 1000);
            sb.append(" and ur.ctAt <=").append(Times.d2TS(Times.D(searchDate[1])) * 1000);
        }
        sb.append(" order by ur.ctAt desc");
        return dbService.listPage(UserRebateVO.class, pageNumber, pageSize, sb.toString());
    }

    @Override
    public BigDecimal searchSum(String conditionData, String orderNo, String fromUserSearch, String toUserSearch, String[] searchDate) {
        StringBuffer sb = new StringBuffer();
        sb.append(" SELECT IFNULL(sum(ur.rebateMoney), 0)");
        sb.append(" FROM user_rebate ur");
        sb.append(" LEFT JOIN crown_order o ON ur.orderId = o.id");
        sb.append(" LEFT JOIN user u1 ON ur.fromUser = u1.id");
        sb.append(" LEFT JOIN user u2 ON ur.toUser = u2.id");
        sb.append(" WHERE 1=1");
        if (Strings.isNotBlank(conditionData)) {
            String[] split = conditionData.split(",");
            for (String col : split) {
                String colName = UserColEnum.getValByName(col);
                if (Strings.isNotBlank(colName)) {
                    // 默认不显示游客、内部账号
                    sb.append(" AND u2.").append(colName).append(" = 0");
                }
            }
        }
        if (Strings.isNotBlank(orderNo)) {
            sb.append(" AND o.no = '").append(orderNo).append("'");
        }

        // 按昵称/邮箱/订单号搜索
        if (Strings.isNotBlank(fromUserSearch)) {
            sb.append(" AND u1.userName = '").append(fromUserSearch).append("'");
        }
        if (Strings.isNotBlank(toUserSearch)) {
            sb.append(" AND u2.userName = '").append(toUserSearch).append("'");
        }
        // 按时间搜索
        if (null != searchDate && searchDate.length != 0) {
            sb.append(" and ur.ctAt >=").append(Times.d2TS(Times.D(searchDate[0])));
            sb.append(" and ur.ctAt <=").append(Times.d2TS(Times.D(searchDate[1])));
        }
        Sql sql = Sqls.create(sb.toString());
        sql.setCallback(Sqls.callback.str());
        this.dao().execute(sql);
        return new BigDecimal(sql.getString()).setScale(6, BigDecimal.ROUND_DOWN);
    }

    @Override
    public UserRebateVO detail(String id, String userId) {
        //列表sql
        Sql sql = Sqls.create("SELECT ur.*, o.no orderNo, " +
                "u1.nickName fromNickName " +
                "FROM user_rebate ur " +
                "LEFT JOIN crown_order o ON ur.orderId = o.id " +
                "LEFT JOIN user u1 ON ur.fromUser = u1.id " +
                "LEFT JOIN user u2 ON ur.toUser = u2.id " +
                "$condition ");
        Cnd cnd = Cnd.NEW();
        cnd.and("ur.toUser", "=", userId);
        cnd.and("ur.id", "=", id);
        cnd.limit(0, 1);
        sql.setCondition(cnd);
        return dbService.fetchSql(UserRebateVO.class, sql.toString());
    }
}
